import multiprocessing
import os
import random
import time

"""
多进程的设计:
    进程控制

    terminate(self):关闭进程
    is_alive(self):是否存活
    join(self,timeout):加入队列强制执行
    p.is_alive(): 判断子线程p1是否存活
    p.terminate(): 强制结束
    p.Process(daemon=true): 守护进程,主线程开启同时他也开启,主线程结束他也结束
    pid = os.fork() # 创建子进程 只支持linux  windows会报错:Has no attribute fork  
    {pid<0创建失败,pid=0子进程获取数据,pid>0父进程获取数据 }
    psutil :进程工具,pip install psutil 

    # join()
    所有的进程通过start()方法启动,而后多个进程进入到阻塞队列,这时候某一个进程是不可能强占cpu的
    如果这个时候有一个进程必须要现在执行,那就要使用join()
    
# 进程池
        多进程可以提高程序运行效率,但是传统的的多进程模式只适合并发并不多的情况:成百上千的并发进程就不适合使用了,
    会造成资源过多的消耗,导致资源不足的问题,从而降低了系统性能,所以要提高资源的利用率,以及进程的可复用性
    
    
# 管道
        为什么使用管道?
        进程和进程之间不能直接通讯,需要用管道连接两个进程才能通讯
        
# 进程队列(Queue)
    为什么使用对列?(使用场景)
    相当于是一个缓冲区,生产出来的数据,先存到队列(queue)中,然后消费进程从队列中(queue)取出数据
    从而实现进程的数据交互
    
# subprocess
    这个模块是干什么的?
    进行系统和Python的交互
        args,   # 命令
        bufsize=-1, # 缓冲区大小
        stdin=None, # 标准输入
        stdout=None, # 标准输出
        shell=False, # 是否是命令
        cwd=None, # 当前工作路径
        encoding=None, # 编码
        errors=None #编码
        
        # subprocess最强大的功能是
        可以使用标准输入,标准输出,和错误输出,进行进程的数据通信操作
        例子:
            使用脚本调用Python交互式的环境
            像进程执行读写操作
            
# Manger.list()  dict()
    为什么要要用manager.list()?
    实现这10 个进程的 [ 跨进程操作 ]!!!!
    并发执行,但是要求数据的一致性,就要进行进程控制,
    manger = multiprocessing.Manager()# 创建共享数据对象
    
# 并发执行会导致的问题?
    数据的一致性,无法保证
    
# 并发执行的数据一致性解决方案
    block 
    对多进程操作的数据进行上锁,但是程序的性能会因此下降
    
# 信号量机制 semaphore(信号量)
    控制访问,合理分配有限资源
    acquire() 减少资源
    release() 释放资源
    当可用信号量为0 时进程阻塞
    
    
# event 
    多个进程同属于一个event
    一个进程操作event另一个进程就会得到与之相反的状态
    set() 解除阻塞
    wait() 设置阻塞
    clear() 清除状态
"""


# 餐厅处理事件
def restaurant_handler(event):
    print('【{}】1:带领顾客进店,并等待点菜.....'.format(multiprocessing.current_process().name))
    time.sleep(1)# 休眠一秒
    event.set()  # 通知顾客进程操作 2
    event.clear()
    event.wait() # [1] 等待顾客线程操作
    print('【{}】4.后厨拿到菜单,做菜ing: duang....duang...duang....'.format(multiprocessing.current_process().name))
    time.sleep(3)
    print('【{}】5:传菜员从后厨拿菜,端菜路上.....'.format(multiprocessing.current_process().name))
    time.sleep(1)
    event.set() # 通知顾客操作 解除[2]阻塞
    event.clear()

# 顾客处理事件
def customer_handler(event):
    event.wait() # 顾客线程刚开始不能操作
    print('【{}】2:顾客点餐'.format(multiprocessing.current_process().name))
    time.sleep(1)
    print('【{}】3.点餐完毕,等待上菜.....'.format(multiprocessing.current_process().name))
    event.set() # 清除[1]处阻塞
    event.clear()
    event.wait() # [2] 自身进入阻塞,等待上菜线程
    print('【{}】6:菜来喽,干饭......'.format(multiprocessing.current_process().name))
    event.clear()


def main():
    event = multiprocessing.Event()
    p_res = multiprocessing.Process(target=restaurant_handler,args=(event,),name='饭店')
    p_cus = multiprocessing.Process(target=customer_handler,args=(event,),name='顾客')
    p_res.start()
    p_cus.start()
    p_res.join()
    p_cus.join()

if __name__ == '__main__':
    main()